import { expect } from '@jest/globals';
import fse from 'fs-extra';
import path from 'path';

import { WorkerDataEts, WorkerDataTs } from '../../plugins/common-data';
import {
  buildOneHapAndCheckFile,
  commonFileOperation,
  commonJson5Operation,
  listZipEntries,
  readZipEntry,
  updateOneHap
} from '../../plugins/common-fun';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType,
} from '../../plugins/project-builder/models/constants';
import { TestCaseBuilder } from '../../plugins/task-builder/task-case-builder';
import { ProjectBuildOption, TestCaseFun } from '../../plugins/task-builder/test-case';
import { TestTaskOptionBuilder } from '../../plugins/task-builder/test-task-option';

const stageProjectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  }
};

const faProjectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.FA,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.EmptyAbility
  }
};

const testFun: TestCaseFun = async (project, taskConfig, record) => {
  // 1. 新增worker后全量编译hap
  const moduleRootPath = project.getModule('entry').moduleRootPath();
  const WorkerData = project.option.apiType === APIType.STAGE ? WorkerDataEts : WorkerDataTs;
  const extendStr = project.option.apiType === APIType.STAGE ? 'ets' : 'ts';
  await fse.ensureDir(path.resolve(moduleRootPath, 'src/main/ets/workers'));
  await fse.writeFile(path.resolve(moduleRootPath, `src/main/ets/workers/Worker.${extendStr}`), WorkerData);
  await commonJson5Operation(path.resolve(moduleRootPath, 'build-profile.json5'), async (json5: any) => {
    json5.buildOption.sourceOption = {
      'workers': [
        `./src/main/ets/workers/Worker.${extendStr}`,
      ]
    };
  });
  await buildOneHapAndCheckFile('entry')(project, taskConfig, record);
  const files = await fse.readdir(path.resolve(moduleRootPath, 'build/default/outputs/default'));
  const hapName = files.find(item => item.endsWith('.hap'));
  const hapPath = path.resolve(moduleRootPath, `build/default/outputs/default/${hapName}`);
  const workerStagePath = 'entry|entry|1.0.0|src/main/ets/workers/Worker.ts';
  const workerFaPath = 'assets/js/workers/Worker.abc';

  let oldWorkMappings;
  if (project.option.apiType === APIType.STAGE) {
    const sourceMapsContent = await readZipEntry(hapPath, 'ets/sourceMaps.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    expect(workerStagePath in sourceMap).toBe(true);
    oldWorkMappings = sourceMap[workerStagePath]['mappings'];
  } else {
    const entries = (await listZipEntries(hapPath)).map(item => item[0]);
    expect(entries.includes(workerFaPath)).toBe(true);
    const sourceMapsContent = await readZipEntry(hapPath, 'assets/js/workers/Worker.js.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    oldWorkMappings = sourceMap['mappings'];
  }

  // 修改worker文件内容后增量编译, 判断增量编译后，mappings内容产生变更
  // eslint-disable-next-line max-len
  await commonFileOperation(path.resolve(moduleRootPath, `src/main/ets/workers/Worker.${extendStr}`), async (buffer: Buffer) => {
    const content = buffer.toString();
    content.replace('{\n}', '{\n   console.log(e.type)\n }');
    return '';
  });
  await updateOneHap('entry')(project, taskConfig, record);
  if (project.option.apiType === APIType.STAGE) {
    const sourceMapsContent = await readZipEntry(hapPath, 'ets/sourceMaps.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    expect(workerStagePath in sourceMap).toBe(true);
    expect(sourceMap[workerStagePath]['mappings'] === oldWorkMappings).toBe(false);
  } else {
    const entries = (await listZipEntries(hapPath)).map(item => item[0]);
    expect(entries.includes(workerFaPath)).toBe(true);
    const sourceMapsContent = await readZipEntry(hapPath, 'assets/js/workers/Worker.js.map');
    const sourceMap = sourceMapsContent ? JSON.parse(sourceMapsContent!) : {};
    expect(sourceMap['mappings'] === oldWorkMappings).toBe(false);
  }
};

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Incremental_Compilation_hos_api10_Stage_Ets_Open_Update_013')
  .description('增量编译-修改worker进行增量编译校验')
  .projectBuilderOption(stageProjectBuilderOption)
  .taskConfig(TestTaskOptionBuilder.builder().caseLevel(CaseLevel.L1).build())
  .testFun(testFun)
  .load();

TestCaseBuilder.builder()
  .caseName('OPENLAB_AIDE_ZOS_Build_Incremental_Compilation_api10_FA_Ets_Open_Update_010')
  .description('005.增量编译-修改worker进行增量编译校验')
  .projectBuilderOption(faProjectBuilderOption)
  .taskConfig(TestTaskOptionBuilder.builder().caseLevel(CaseLevel.L1).build())
  .testFun(testFun)
  .load();
